package scutiger.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.log4j.Logger;
import scutiger.annotation.BaseController;
import scutiger.impl.LBean;
import scutiger.impl.LMethod;
import scutiger.provider.GlobalException;
import scutiger.provider.SimpleGlobalException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ServletUtil {

    private static Logger logger = Logger.getLogger(ServletUtil.class.getName());

    private final static String SUFFIX = "/main";
    private final static String  SEPARATOR = "/";

    private final static String NOT_FOUND_CONTROLLER = "请求的控制器找不到";
    private final static String ACCESS_REFUSE = "访问被拒绝,请先登录";
    private final static String NOT_FOUND_FUNCTION = "该控制器没有该方法";

    private final static String PARAM_IS_NULL_NOT_TO_INTEGER = "前端传过来的参数为Null 不能转化为Integer";
    private final static String PARAM_IS_NULL_NOT_TO_DOUBLE = "前端传过来的参数为Null 不能转化为Double";
    private final static String PARAM_IS_NULL_NOT_TO_LONG = "前端传过来的参数为Null 不能转化为Long";
    private final static String JSON_DATA_ERROR = "JSON数据有误";
    private final static String ERROR = "服务器发生了错误";
    private final static String [] types = {"int","double","bool","long"};

    public static void print(HttpServletResponse response,String msg){
        try {
            String out_msg = "请求的资源找不到";
            if(!StringUtils.isEmpty(msg)){
                out_msg = msg;
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("result",true);
            jsonObject.put("msg",out_msg);
            String s = jsonObject.toJSONString();
            response.getWriter().print(s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private static String transformToController(String uri){
        Map<String, LBean> beans = LEIClassLoader.getMapControllers();
        if(StringUtils.isEmpty(uri)){
            return null;
        }
        String[] split = uri.replaceFirst(SEPARATOR,"").split(SEPARATOR);
        String controller = "";
        String temp = "";
        for (String key : split) {
            temp=temp+SEPARATOR+key;
            if(beans.containsKey(temp)){
                controller = temp;
                break;
            }
        }
        return controller;
    }

    public static void toRun(HttpServletRequest request, HttpServletResponse response){
       //首先获取请求路径的方法
       String uri = request.getRequestURI();
       uri = uri.replaceFirst(SUFFIX,"");

       String controller = transformToController(uri);

       if(StringUtils.isEmpty(controller)){
           response.setStatus(HttpServletResponse.SC_NOT_FOUND);
           print(response,NOT_FOUND_CONTROLLER);
           return;
       }

       // 替换掉控制器剩下的就是方法
       String method = uri.replaceFirst(controller,"");

       try {
           Map<String, LBean> beans = LEIClassLoader.getMapControllers();
           LBean bean = beans.get(controller);

           // 校验是否登录
           if(bean.isCheckLogin()){
               Object currentID = request.getSession(true).getAttribute("CurrentID");
               if(currentID == null){
                   response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                   print(response,ACCESS_REFUSE);
                   return;
               }
           }

           Class clazz = bean.getAClass();
           Object object = LEIClassLoader.getNewInstance(clazz);

           Map<String, LMethod> leiMethodMap = bean.getLEIMethodMap();
           Map<String,Integer> leiMethodMapIndex = bean.getLEIMethodMapIndex();
           LMethod leiMethod1 = leiMethodMap.get(method);

           if(leiMethod1 == null){
               response.setStatus(HttpServletResponse.SC_NOT_FOUND);
               print(response,NOT_FOUND_FUNCTION);
               return;
           }

           Method method4 = leiMethod1.getMethod();
           //设置request和response
           LEIClassLoader.initServlet(object,leiMethodMapIndex,request,response);


           //参数类型
           Class<?>[] paramTypes = leiMethod1.getParamTypes();
           //泛型参数列表
           Type[] genericParameterTypes = leiMethod1.getGenericParameterTypes();
           //参数名称
           String[] paramNames = leiMethod1.getParamNames();
           //默认值
           String[] defaultValues = leiMethod1.getDefaultValues();
           //参数
           Object[] params = new Object[paramTypes.length];
           for (int i = 0; i < paramTypes.length; i++) {
               String paramName = paramNames[i];
               Class<?> paramType = paramTypes[i];
               String parameter = request.getParameter(paramName);
               parameter = StringUtils.isEmpty(parameter)&&!StringUtils.isEmpty(defaultValues[i])?defaultValues[i]:parameter;

               if(paramType == String.class){
                   params[i] = parameter;
               }else if(paramType == Integer.class||paramType.getName().toLowerCase().contains(types[0])){
                   if(StringUtils.isEmpty(parameter)){
                       response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                       print(response,paramName+PARAM_IS_NULL_NOT_TO_INTEGER);
                       return;
                   }
                   params[i] = Integer.valueOf(parameter);
               }else if(paramType == Double.class||paramType.getName().toLowerCase().contains(types[1])){
                   if(StringUtils.isEmpty(parameter)){
                       response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                       print(response,paramName+PARAM_IS_NULL_NOT_TO_DOUBLE);
                       return;
                   }
                   params[i] = Double.valueOf(parameter);
               }else if(paramType == Long.class||paramType.getName().toLowerCase().contains(types[3])){
                   if(StringUtils.isEmpty(parameter)){
                       response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                       print(response,paramName+PARAM_IS_NULL_NOT_TO_LONG);
                       return;
                   }
                   params[i] = Long.valueOf(parameter);
               }else if(paramType == Boolean.class||paramType.getName().toLowerCase().contains(types[2])){
                   params[i] = StringUtils.transformBoolean(parameter);
               }else{
                   try{
                       if(parameter != null){
                           if(paramType == List.class&&genericParameterTypes.length>0){
                               Type genericType = ((ParameterizedType) genericParameterTypes[i]).getActualTypeArguments()[0];
                               JSONArray jsonArray = JSON.parseArray(parameter);
                               List list = new ArrayList();
                               for (int i1 = 0; i1 < jsonArray.size(); i1++) {
                                   Class classByName = LEIClassLoader.getClassByName(genericType.getTypeName());
                                   Object object1 = JSON.toJavaObject(jsonArray.getJSONObject(i1),classByName);
                                   list.add(object1);
                               }
                               params[i] = list;
                           }else{
                               params[i] = JSON.parseObject(parameter, paramType);
                           }
                       }else{
                           params[i] = null;
                       }
                   }catch (Exception e){
                       e.printStackTrace();
                       response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                       print(response,paramName+JSON_DATA_ERROR);
                       return;
                   }
               }
           }

           String threadName = Thread.currentThread().getName();
           logger.info("当前线程:" + Thread.currentThread().getName());
           logger.info("controller:地址:" + object);
           //新增一个当前线程的Map
           LEIClassLoader.currentThreadSingleBeans.put(threadName,new HashMap<>());
           //1.字段自动注入
           LEIClassLoader.autowired(object);
           // 注入完成后清除当前线程的Map
           LEIClassLoader.currentThreadSingleBeans.remove(threadName);
           //2.执行方法
           LEIClassLoader.invoke(object,method4,leiMethodMapIndex,params);

       } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
           runException(e);
           response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
           print(response,ERROR);
       }

   }

    /**执行所有的exception 包括自定义的实现
     *
     * @param e 全局异常信息
     */
   private static void runException(Exception e){
       List<Class> classByPackages = LEIClassLoader.getImplClasses(GlobalException.class, new SimpleGlobalException());
       for (Class clazz : classByPackages) {
           try {
               GlobalException globalException = (GlobalException) clazz.newInstance();
               globalException.exception(e);
           } catch (InstantiationException | IllegalAccessException ex) {
               ex.printStackTrace();
           }
       }
   }

}
